#include "netinterfaceinfo.h"
#include <thread>
#include <chrono>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
#include <cstring>
#include <map>
#include <iomanip>
#include <math.h>
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock2.h>
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <unistd.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#endif

// 端口服务映射表（可扩展）
static const std::map<unsigned short, std::string> SERVICE_MAP = {
    {20, "FTP-DATA"}, {21, "FTP"}, {22, "SSH"}, {23, "Telnet"},
    {25, "SMTP"}, {53, "DNS"}, {67, "DHCP-Server"}, {68, "DHCP-Client"},
    {80, "HTTP"}, {110, "POP3"}, {123, "NTP"}, {143, "IMAP"},
    {443, "HTTPS"}, {465, "SMTPS"}, {587, "SMTP-submission"}, {993, "IMAPS"},
    {995, "POP3S"}, {1433, "MSSQL"}, {1521, "OracleDB"}, {1723, "PPTP"},
    {3306, "MySQL"}, {3389, "RDP"}, {5432, "PostgreSQL"}, {5900, "VNC"},
    {6379, "Redis"}, {8080, "HTTP-Proxy"}, {8443, "HTTPS-Alt"}, {9090, "Websphere"}
};

// 网络手法数据信息
struct NetTxRxInfo {
    double dRxBytes = 0; // 接收数据，Bytes
    double dTxBytes = 0; // 发送数据，Bytes
};

static volatile bool gs_bRunning = false; // 网络监测线程运行标识
static volatile int gs_iGapSeconds = 30; // 网络监测间隔，默认30s
static volatile double gs_dRxSpeedKBs = 0; // 接收速率-下行 (KB/s)
static volatile double gs_dTxSpeedKBs = 0; // 发送速率-上行 (KB/s)
static std::thread gs_th4NetStateMonitor; // 网络状态监测线程

// 解析端口号（十六进制转十进制）
static unsigned short parsePort(const std::string& hex_port)
{
    return static_cast<unsigned short>(std::stoul(hex_port, nullptr, 16));
}

/******************************************************************
 * 功能：获取当前系统秒值的时间戳
 * ****************************************************************/
static uint64_t getCurSystemSecTime()
{
    return static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::seconds>
                                 (std::chrono::system_clock::now().time_since_epoch()).count()); // 秒
}

#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
// Windows实现获取网络接口信息
static void getWindowsNetInterfaceInfo(NetInterfaceInfo& stInfos)
{
    return;
}
#else
// Linux获取TCP/UDP监听端口信息
static void getLinuxListeningPorts(const std::string& filename, const std::string& protocol, std::vector<OpenProtInfo>& vtPortInfos)
{
    std::ifstream file(filename);
    if (!file.is_open()) {
        printf("[getListeningPorts] >>> open file (%s) failed.\r\n", filename.data());
        return;
    }

    std::string line = "";
    // 跳过标题行
    std::getline(file, line);

    while (std::getline(file, line)) {
        std::istringstream iss(line);
        std::vector<std::string> tokens;
        std::string token;

        // 分割行数据
        while (iss >> token) {
            tokens.push_back(token);
        }

        // 确保有足够的数据字段
        if (tokens.size() < 10) continue;

        // 检查状态：TCP需要状态为0A(LISTEN)，UDP总是显示
        if (protocol == "tcp" && tokens[3] != "0A") continue;

        // 解析本地地址:端口
        std::string local_addr = tokens[1];
        size_t colon_pos = local_addr.find(':');
        if (colon_pos == std::string::npos) continue;

        OpenProtInfo stPortInfo;
        stPortInfo.strProtocol = protocol;

        // 提取端口号
        stPortInfo.usPort = parsePort(local_addr.substr(colon_pos + 1));

        // 获取服务名称
        auto it = SERVICE_MAP.find(stPortInfo.usPort);
        if (it != SERVICE_MAP.end()) {
            stPortInfo.srtServiceType = it->second;
        } else {
            stPortInfo.srtServiceType = "Unknown";
        }

        vtPortInfos.emplace_back(stPortInfo);
    }

    return;
}

// Linux实现获取网卡信息
static void getLinuxNetCardInfo(std::vector<std::string>& vtNetCardInfos)
{
    std::ifstream file("/proc/net/dev");
    std::string line = "";

    // 跳过前两行标题
    std::getline(file, line);
    std::getline(file, line);

    while (std::getline(file, line)) {
        // 移除行首空格
        size_t start = line.find_first_not_of(" ");
        if (start != std::string::npos) {
            line = line.substr(start);
        }

        // 提取接口名（直到冒号）
        size_t colon_pos = line.find(':');
        if (colon_pos == std::string::npos) continue;
        std::string ifacename = line.substr(0, colon_pos);
        if (ifacename.find("lo") != std::string::npos) continue; // 跳过回环接口
        vtNetCardInfos.emplace_back(ifacename);
    }

    return;
}

// Linux实现获取网卡数据信息
static void getLinuxNetSpeed(NetTxRxInfo& stInfo)
{
    std::ifstream file("/proc/net/dev");
    std::string line = "";

    // 跳过前两行标题
    std::getline(file, line);
    std::getline(file, line);

    while (std::getline(file, line)) {
        // 移除行首空格
        size_t start = line.find_first_not_of(" ");
        if (start != std::string::npos) {
            line = line.substr(start);
        }

        // 提取接口名（直到冒号）
        size_t colon_pos = line.find(':');
        if (colon_pos == std::string::npos) continue;
        std::string ifacename = line.substr(0, colon_pos);
        if (ifacename.find("lo") != std::string::npos) continue; // 跳过回环接口

        // 解析剩余数据
        std::istringstream iss(line.substr(colon_pos + 1));
        unsigned long long rx_bytes = 0; // 接收字节数（下行）
        unsigned long long tx_bytes = 0; // 发送字节数（上行）

        iss >> rx_bytes; // 接收字节
        // 跳过中间字段（共7个）
        for (int i = 0; i < 7; ++i) {
            unsigned long long tmp;
            iss >> tmp;
        }
        iss >> tx_bytes; // 发送字节

        //printf("name: %s, %llu Bytes, %llu Bytes\r\n", ifacename.data(), rx_bytes, tx_bytes);
        // 总的网速
        stInfo.dRxBytes += static_cast<double>(rx_bytes);
        stInfo.dTxBytes += static_cast<double>(tx_bytes);
    }

    return;
}

// Linux实现获取网络接口信息
static void getLinuxNetInterfaceInfo(NetInterfaceInfo& stInfos)
{
    // 获取网速信息
    stInfos.dRxSpeedKBs = gs_dRxSpeedKBs;
    stInfos.dTxSpeedKBs = gs_dTxSpeedKBs;

    // 获取网卡信息
    getLinuxNetCardInfo(stInfos.vtEthNames);

    // 获取开放端口信息
    // 获取tcp类型的端口信息
    std::vector<OpenProtInfo> vtTcpPortInfos;
    getLinuxListeningPorts("/proc/net/tcp", "tcp", vtTcpPortInfos);

    // 获取udp类型的端口信息
    std::vector<OpenProtInfo> vtUdpPortInfos;
    getLinuxListeningPorts("/proc/net/udp", "udp", vtTcpPortInfos);

    // 合并端口信息
    std::map<unsigned short, OpenProtInfo> mp4AllPortsInfo;
    for (const auto& info : vtTcpPortInfos) {
        mp4AllPortsInfo[info.usPort] = info;
    }

    for (const auto& info : vtUdpPortInfos) {
        // 如果端口已存在（TCP和UDP同时开放）
        if (mp4AllPortsInfo.find(info.usPort) != mp4AllPortsInfo.end()) {
            // 更新信息
            mp4AllPortsInfo[info.usPort].strProtocol = mp4AllPortsInfo[info.usPort].strProtocol + "&" + info.strProtocol;
            mp4AllPortsInfo[info.usPort].srtServiceType = mp4AllPortsInfo[info.usPort].srtServiceType + "+" + info.srtServiceType;
        } else {
            mp4AllPortsInfo[info.usPort] = info;
        }
    }

    //printf(">>> Open port number: %lu\r\n", mp4AllPortsInfo.size());
    //for (const auto& [port, info] : mp4AllPortsInfo) {
    for (auto iter = mp4AllPortsInfo.begin(); iter != mp4AllPortsInfo.end(); ++iter) {
        //printf(">>> Open port: %u, %s, %s\r\n", iter->second.usPort, iter->second.strProtocol.data(), iter->second.srtServiceType.data());
        stInfos.vtPortInfos.emplace_back(iter->second);
    }

    return;
}
#endif

// 网络监测线程执行函数
static void pfnNetStateMonitor()
{
    pthread_setname_np(pthread_self(), "NetStateMonitor"); // 设置线程名称
    uint64_t iPreSeconds = getCurSystemSecTime(); // 获取当前时间信息

    // 获取当前网络数据信息，并进行初始化
    NetTxRxInfo stPreInfo;
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
    // TODO
#else
    getLinuxNetSpeed(stPreInfo);
#endif

    while (gs_bRunning) {
        uint64_t iCurSeconds = getCurSystemSecTime();
        if (static_cast<uint64_t>(gs_iGapSeconds) < (iCurSeconds - iPreSeconds)) {
            // 时间满足了，进行网速计算
            NetTxRxInfo stCurInfo;
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
            // TODO
#else
            getLinuxNetSpeed(stCurInfo); // 获取当前网络数据信息
#endif
            // 获取到的是字节，需要转换为千字节
            gs_dRxSpeedKBs = (fabs(stCurInfo.dRxBytes - stPreInfo.dRxBytes) / 1024.0) / gs_iGapSeconds * 1.0;
            gs_dTxSpeedKBs = (fabs(stCurInfo.dTxBytes - stPreInfo.dTxBytes) / 1024.0) / gs_iGapSeconds * 1.0;

            iPreSeconds = iCurSeconds;
            stPreInfo = stCurInfo;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 切换CPU时间
    }

    return;
}

/********************************************************
 * 功能：开始网络状态监测，目前主要是监测网速
 * 输入参数：
 *      iSeconds：监测间隔，单位秒
 * ******************************************************/
void startNetStateMonitor(int iSeconds)
{
    if (!gs_bRunning) {
        gs_bRunning = true;
        gs_iGapSeconds = iSeconds;

        gs_th4NetStateMonitor = std::thread(pfnNetStateMonitor);
    }

    return;
}

/********************************************************
 * 功能：停止网络状态监测
 * ******************************************************/
void stopNetStateMonitor()
{
    if (gs_bRunning) {
        gs_bRunning = false;

        if (gs_th4NetStateMonitor.joinable()) {
            gs_th4NetStateMonitor.join();
        }
    }

    return;
}

/********************************************************
 * 功能：获取网络接口信息
 * 输出参数：
 *      stInfos：网络接口信息
 * ******************************************************/
void getNetInterfaceInfo(NetInterfaceInfo& stInfos)
{
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
    getWindowsNetInterfaceInfo(stInfos);
#else
    getLinuxNetInterfaceInfo(stInfos);
#endif
    return;
}

